/**
  ******************************************************************************
  * @file    Libraries/Device/JS32T031/js32t031_selfcheck.c
  * @author  JUSHENG Application Team
  * @version V1.0.0
  * @date    02-19-2022
  * @brief   
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT 2022 JUSHENG</center></h2>
  *
  *
  *
  ******************************************************************************
  */ 
  
/* Includes ------------------------------------------------------------------*/
#include "include.h"

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/

/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/


#if defined(__CC_ARM)                /* KEIL Compiler */

 __asm void __cpu_check(void)
{
    
    //r13(sp) r14(lr) r15(pc) cpsr[n z c v ] spsr
    
    PRESERVE8
    EXTERN SelfCheckError

    PUSH  {lr}

    // r0 [31:1]
    LDR r0, =0xfffffffe 
    SUBS r0,r0,#4
    ADD r0,PC
    ADDS r0,r0,#4
    MOV PC,r0
  
    //N Z C V 
    LDR r0, =0x7ffffffe 
    BVS  SELF_CHECK_ERR    //V=1
    BMI  SELF_CHECK_ERR    //N=1
    ADCS r0,r0,r0
    BVC  SELF_CHECK_ERR    //V=0
    BPL  SELF_CHECK_ERR    //N=0
    BCS  SELF_CHECK_ERR    //C=1
    BEQ  SELF_CHECK_ERR    //Z=1
    ADDS r0,r0,#4
    BCC  SELF_CHECK_ERR    //C=0 
    BNE  SELF_CHECK_ERR    //Z=0

    MOVS r0,#1
    BEQ  SELF_CHECK_ERR    //Z=1
    
    LDR r0, =0xffffffff 
    MOV lr,r0 
    CMP lr, r0
    BNE  SELF_CHECK_ERR
    MOVS r0,#0 
    MOV lr,r0 
    BNE  SELF_CHECK_ERR

    MOV lr,sp
    
    LDR r0, =0xfffffffc 
    MOV sp,r0 
    CMP sp, r0
    BNE  SELF_CHECK_ERR
    MOVS r0,#0 
    MOV sp,r0 
    BNE  SELF_CHECK_ERR
    
    MOV sp,lr

    POP  {PC}
    
SELF_CHECK_ERR
    BL.W  SelfCheckError   
      
}
__attribute__((aligned(4))) __asm void __cpu_r1_r12_check(void)
 { 
//    MOVS r0,#0x10 
//    LDMIA r0!,{R1-R7}

    NOP
    PUSH  {lr}

    LDR r0, =0xaaaaaaaa     
    MOV lr, r0
    
  
L0  MVNS r0, r0
    MOV r1, r0
    CMP r1, r0
    BNE  SELF_CHECK_ERR
    MOV r2, r0
    CMP r2, r0
    BNE  SELF_CHECK_ERR
    MOV r3, r0
    CMP r3, r0
    BNE  SELF_CHECK_ERR
    MOV r4, r0
    CMP r4, r0
    BNE  SELF_CHECK_ERR
    MOV r5, r0
    CMP r5, r0
    BNE  SELF_CHECK_ERR
    MOV r6, r0
    CMP r6, r0
    BNE  SELF_CHECK_ERR 
    MOV r7, r0
    CMP r7, r0
    BNE  SELF_CHECK_ERR
    MOV r8, r0
    CMP r8, r0
    BNE  SELF_CHECK_ERR
    MOV r9, r0
    CMP r9, r0
    BNE  SELF_CHECK_ERR 
    MOV r10, r0
    CMP r10, r0
    BNE  SELF_CHECK_ERR 
    MOV r11, r0
    CMP r11, r0
    BNE  SELF_CHECK_ERR 
    MOV r12, r0
    CMP r12, r0
    BNE  SELF_CHECK_ERR 
       
    CMP lr, r0
    BNE L0

    POP  {PC}
 }



#if 0
__attribute__((aligned(4))) __asm void __ram_check_all_1(u32* start_addr, u16 len)
{
    MOV      r2, r0
    MOV      r0, r2
    MOV      r3, r1
    B        L11

L10 MOVS     r4,#0x00
    MVNS     r4,r4
    STR      r4,[r0,#0x00]
    LDM      r0!,{r4}
    ADDS     r4,r4,#1
    CMP      r4,#0x00
    BEQ      L11 
    BL.W     SelfCheckError
    
L11 MOV      r4,r3
    SUBS     r5,r3,#1
    UXTH     r3,r5
    CMP      r4,#0x00
    BNE      L10


    MOV      r0, r2
    MOV      r3, r1
    B        L13

L12 MOVS     r4,#0x00
    STR      r4,[r0,#0x00]
    LDM      r0!,{r5}
    CMP      r5,#0x00
    BEQ      L13
    BL.W     SelfCheckError

L13 MOV      r4, r3
    SUBS     r5,r3,#1
    UXTH     r3,r5
    CMP      r4,#0x00
    BNE      L12 
     
    //MOV      pc, lr
    BX       lr 
}

//void __ram_check_up(u32* start_addr, u16 len)
//{
//    u32 *p;
//    u16 cnt;
// 
//    p = (u32 *)start_addr;
//    cnt = len;
//    while(cnt--)
//    {
//        *p = 0xffffffff;
//        if (*p++ != 0xffffffff)
//             SelfCheckError();
//    }    
//    
//    p = (u32 *)start_addr;
//    cnt = len;
//    while(cnt--)
//    {
//        *p = 0;
//        if(*p++ != 0)
//             SelfCheckError();
//    }
//}
#endif

#if 0
__attribute__((aligned(4))) __asm void __ram_check_down(u32* start_addr, u16 len)
{
    MOV      r2,r0
    LSLS     r4,r1,#2
    ADDS     r4,r4,r2
    SUBS     r0,r4,#4
    MOV      r3,r1
    B        L21  
     
L20        
    MOVS     r4,#0x00
    MVNS     r4,r4
    STR      r4,[r0,#0x00] 
    LDR      r4,[r0,#0x00]
    SUBS     r0,r0,#4
    ADDS     r4,r4,#1
    CMP      r4,#0x00
    BEQ      L21      
    BL.W     SelfCheckError  
L21
    MOV      r4,r3
    SUBS     r5,r3,#1
    UXTH     r3,r5
    CMP      r4,#0x00
    BNE      L20        
   
    LSLS     r4,r1,#2
    ADDS     r4,r4,r2
    SUBS     r0,r4,#4
    MOV      r3,r1
    B        L23

L22 
    MOVS     r4,#0x00
    STR      r4,[r0,#0x00]
    LDR      r5,[r0,#0x00]
    SUBS     r0,r0,#4
    CMP      r5,#0x00
    BEQ      L23
    BL.W     SelfCheckError 
L23      
    MOV      r4,r3
    SUBS     r5,r3,#1
    UXTH     r3,r5
    CMP      r4,#0x00
    BNE      L22
     
    MOV      pc, lr
}

#endif

#if 1
__attribute__((aligned(4))) __asm void __ram_check_all(u32* start_addr, u16 len)
{

    PUSH     {r4-r7}
    SUBS     r6,r1,#1

    MOV      r2,r0
    UXTH     r5,r6
    CMP      r1,#0x00

    BEQ      L33
    MOVS     r7,#0x00

L30     
    STRB     r7,[r2,#0x00]
    MOVS     r3,#0x01

L31      
    LDRB     r4,[r2,#0x00]
    ORRS     r4,r4,r3
    STRB     r4,[r2,#0x00]

    TST      r4,r3
    //BNE      L32
    BEQ      L3E      
    //BL.W     SelfCheckError 

//L32
    LSLS     r3,r3,#1
    LSLS     r3,r3,#24
    LSRS     r3,r3,#24
    BNE      L31

    MOV      r3,r5
    SUBS     r5,r5,#1
    ADDS     r2,r2,#1
    UXTH     r5,r5
    CMP      r3,#0x00
    BNE      L30

L33
    UXTH     r3,r6
    CMP      r1,#0x00
    BEQ      L37

L34       
    MOVS     r1,#0x01
L35     
    LDRB     r2,[r0,#0x00]
    BICS     r2,r2,r1
    STRB     r2,[r0,#0x00]

    TST      r2,r1
    BEQ      L36
L3E
    BL.W     SelfCheckError 

L36
    LSLS     r1,r1,#1
    LSLS     r1,r1,#24
    LSRS     r1,r1,#24
    BNE      L35

    MOV      r1,r3
    SUBS     r3,r3,#1
    ADDS     r0,r0,#1
    UXTH     r3,r3
    CMP      r1,#0x00
    BNE      L34
L37      
    POP      {r4-r7} 
    //MOV      pc, lr
    BX       lr
}

//void __ram_check_all(u8* start_addr, u16 len)
//{
//    u8 *p;
//    u16 cnt;
// 
//    p = (u8 *)start_addr;
//    cnt = len;
//    while(cnt--)
//    {
//        *p = 0;
//        for(u8 i=1;i!=0x0; i=i<<1)
//        {
//            *p |= i;
//            if ((*p & i ) == 0)
//              SelfCheckError();            
//        }
//        p++;    
//            
//    }    

//    p = (u8 *)start_addr;
//    cnt = len;
//    while(cnt--)
//    {
//        for(u8 i=1;i!=0x0; i=i<<1)
//        {
//            *p &= ~i;
//            if ((*p & i ) != 0)
//              SelfCheckError();            
//        }
//        p++;    
//            
//    }      

//}

#endif


#endif

#if 1
void __ram_check_up(u32* start_addr, u16 len)
{
    u32 *p;
    u16 cnt;
 
    p = (u32 *)start_addr;
    cnt = len;
    while(cnt--)
    {
        *p = 0xffffffff;
        if (*p++ != 0xffffffff)
             SelfCheckError();
    }    
    
    p = (u32 *)start_addr;
    cnt = len;
    while(cnt--)
    {
        *p = 0;
        if(*p++ != 0)
             SelfCheckError();
    }
}
#endif

#if 1
void __ram_check_down(u32* start_addr, u16 len)
{
    u32 *p;
    u16 cnt;
 
    p = start_addr + len - 1;
    cnt = len;
    while(cnt--)
    {
        *p = 0xffffffff;
        if (*p-- != 0xffffffff)
             SelfCheckError();
    }    
    
    p = start_addr + len - 1;
    cnt = len;
    while(cnt--)
    {
        *p = 0;
        if(*p-- != 0)
             SelfCheckError();
    }

}
#endif


void __clk_check(u32 u_thrd, u32 l_thrd)
{
    u32 soft_hirc;
    u16 lirc;
       
    SYSCTRL->SYS_KEY = 0x3fac87e4;
    
    SYSCTRL->SYS_CON0 &= ~(0x1 << 6);       // reset timer;
    __NOP();__NOP();__NOP();__NOP();__NOP();
    SYSCTRL->SYS_CON0 |= (0x1 << 6);
    

    lirc = (u16)((*((volatile u32 *)(0x1FF01234))) & 0xFFFF);

    
    TIMER0->TMR_CON = LL_TIMER_CON_DIVISION_SET(LL_TIMER_PSC_NONE) | 
                            LL_TIMER_CON_SRC_SEL(LL_TIMER_SRC_INTERNAL_LOW_SPEED_RC_DIV_2) |  //32k
                            LL_TIMER_CON_MODE_SET(LL_TIMER_MODE_SEL_PWM)|
                            LL_TIMER_CON_SYNCO_SEL(LL_TIMER_SYNCO_SEL_PWM)|
                            LL_TIMER_CON_PWM_POL |
                            LL_TIMER_CON_EDGE_SEL(0x3);
    TIMER0->TMR_CLR |= LL_TIMER_CLR_ALL_PENDING;
    TIMER0->TMR_CAP1 = lirc/50;
    TIMER0->TMR_CAP2 = lirc/100;            // 10ms    
    TIMER0->TMR_CAP3 = (lirc/50) | (((lirc/100) << 16) & 0xFFFF0000);
    
    TIMER1->TMR_CON = LL_TIMER_CON_DIVISION_SET(LL_TIMER_PSC_8) | 
                            LL_TIMER_CON_SRC_SEL(LL_TIMER_SRC_SYS_RISING) | 
                            LL_TIMER_CON_SLAVE_MODE(LL_TIMER_SLAVE_MODE_GATING)|
                            LL_TIMER_CON_GATE_KEEP_MODE_SEL;
    TIMER1->TMR_CAP1 = 0xFFFF;  
    TIMER1->TMR_CAP3 = 0xFFFF | ((0 << 16) & 0xFFFF0000);
    TIMER1->TMR_CLR |= LL_TIMER_CLR_CNT_PRD_PENDING | LL_TIMER_CLR_CNT_OVERFLOW_PENDING;


    TIMER_ALL->TMR_ALLCON = LL_TIMER_ALLCON_TIMER0_CNT_CLR | LL_TIMER_ALLCON_TIMER1_CNT_CLR;
    TIMER_ALL->TMR_ALLCON = LL_TIMER_ALLCON_TIMER0_START | LL_TIMER_ALLCON_TIMER1_START;

//    ll_timer_all_sync_mode_set(TIMER_ALL, LL_TIMER_ALLCON_TIMER0_CNT_CLR | LL_TIMER_ALLCON_TIMER1_CNT_CLR);
//    ll_timer_all_sync_mode_set(TIMER_ALL, LL_TIMER_ALLCON_TIMER0_START | LL_TIMER_ALLCON_TIMER1_START);
   
   
    while(!LL_TIMER_CNT_PRD_PENDING_GET(TIMER0));
    TIMER1->TMR_CLR |= LL_TIMER_CLR_ALL_PENDING;
    TIMER1->TMR_EN &= ~LL_TIMER_EN;
    TIMER0->TMR_CLR |= LL_TIMER_CLR_ALL_PENDING;
    TIMER0->TMR_EN &= ~LL_TIMER_EN;

    soft_hirc = TIMER1->TMR_CNT;
    
    if(((soft_hirc << 3) > (u_thrd))||((soft_hirc << 3)< (l_thrd)))
    {
        SelfCheckError();
    }
    
    SYSCTRL->SYS_CON0 &= ~(0x1 << 6);       // reset timer;
    __NOP();__NOP();__NOP();__NOP();__NOP();
    SYSCTRL->SYS_CON0 |= (0x1 << 6);
    
}

void __flash_check(u16 len)
{
    SYSCTRL_REG_OPT(
        SYSCTRL->SYS_CON0 &= ~(0x1 << 25);       // reset crc;
        __NOP();__NOP();__NOP();__NOP();__NOP();
        SYSCTRL->SYS_CON0 |= (0x1 << 25);
    )
    u16 crc_test_len = len - 4;
    if(ll_eflash_crc32(EFLASH, 0, crc_test_len) != (*((volatile u32 *)crc_test_len)))
    {
        SelfCheckError();
    }
}

#if SCL_RUNTIME_EN

u32 selftest_tick = 0;

#if RUNTIME_RAM_EN 
    u16 ram_test_offset  = 0;
#endif

#if RUNTIME_CLK_CHECK_EN    
    TIMER_TypeDef *p_timer_lirc = TIMER0;
#endif

void selfcheck_runtime_init()
{
    selftest_tick = GetSysTick();

#if RUNTIME_CLK_CHECK_EN    
    SYSCTRL_REG_OPT(
        SYSCTRL->SYS_CON0 &= ~(0x1 << 6);       // reset timer;
    __NOP();__NOP();__NOP();__NOP();__NOP();
    SYSCTRL->SYS_CON0 |= (0x1 << 6);
    )

    p_timer_lirc->TMR_CON = LL_TIMER_CON_DIVISION_SET(LL_TIMER_PSC_NONE) | 
                        LL_TIMER_CON_SRC_SEL(LL_TIMER_SRC_INTERNAL_LOW_SPEED_RC_DIV_2) |  //32k
                        LL_TIMER_CON_MODE_SET(LL_TIMER_MODE_SEL_COUNTER);
    p_timer_lirc->TMR_CLR = LL_TIMER_CLR_ALL_PENDING;
    p_timer_lirc->TMR_CAP1 = 0xffff;
    p_timer_lirc->TMR_CAP3 = 0xffff;
    //p_timer_lirc->TMR_EN |= LL_TIMER_EN;
    ram_test_offset = 0xffff;
#endif    
}

void selfcheck_runtime()
{
    if(is_systick_expired(selftest_tick,2000))
    {
        
    #if RUNTIME_CLK_CHECK_EN
        p_timer_lirc->TMR_EN &= ~LL_TIMER_EN;
        u16 lirc = p_timer_lirc->TMR_CNT;
        u16 u_lirc = (u16)(((*((volatile u32 *)(0x1FF01234))) & 0xFFFF)* 1.2);
        u16 l_lirc = (u16)(((*((volatile u32 *)(0x1FF01234))) & 0xFFFF)* 0.8);
        if(ram_test_offset != 0xffff)
        {
            if((lirc > (u_lirc))||(lirc < (l_lirc)))
            {
                SelfCheckError();
            }
        }else
        {
            ram_test_offset = 0;
        }
        
        p_timer_lirc->TMR_CNT = 0;
        p_timer_lirc->TMR_CLR = LL_TIMER_CLR_ALL_PENDING;
    #endif 
        
    #if RUNTIME_CPU_CHECK_EN
        __cpu_r1_r12_check();
    #endif
        
    #if RUNTIME_RAM_EN 
        u32 *p_ram_test_buf = (u32 *)(*((volatile u32 *)(0x00000000 )));      
        u32 ram_test_addr = (*((volatile u32 *)(0x00000000 ))) + ram_test_offset + 8;   
        memcpy(p_ram_test_buf, (u32 *)ram_test_addr, 2*sizeof(u32));    
        __ram_check_up((u32 *)ram_test_addr, 2);
        memcpy((u32 *)ram_test_addr, p_ram_test_buf, 2*sizeof(u32)); 
        if(ram_test_offset < (RAM_LEN - RAM_STACK_LEN - 8))
            ram_test_offset = ram_test_offset + 8;
        else
            ram_test_offset = 0;
    #endif

    #if RUNTIME_FLASH_LEN
        __flash_check(RUNTIME_FLASH_LEN);
    #endif 
        
        selftest_tick = GetSysTick();
        
    #if RUNTIME_CLK_CHECK_EN
        p_timer_lirc->TMR_EN |= LL_TIMER_EN;
    #endif 
    } 
        
}
#endif /*SCL_RUNTIME_EN*/

__attribute__((noinline)) void SelfCheckError(void)
{
    while(1);
}



/*************************** (C) COPYRIGHT 2022 JUSHENG ***** END OF FILE *****/
